package com.ruoyi.lyy.service.impl;

import com.ruoyi.lyy.config.WxPayProperties;
import com.ruoyi.lyy.domain.dto.OrderDTO;
import com.ruoyi.lyy.domain.pojo.Order;
import com.ruoyi.lyy.domain.pojo.OrderDetails;
import com.ruoyi.lyy.mapper.OrderDetailsMapper;
import com.ruoyi.lyy.mapper.OrderMapper;
import com.ruoyi.lyy.service.IWxPayService;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.time.LocalDateTime;
import java.util.*;

/**
 * @author YueYang
 * Created on 2025/11/18 16:44
 * @version 1.0
 */
@Slf4j
@Service
public class WxPayServiceImpl implements IWxPayService {

    @Autowired
    private WxPayProperties wxPayProperties;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailsMapper orderDetailsMapper;


    /**
     * 获取预支付信息
     *
     * @return 预支付信息 加上生成的订单id
     */
    @Transactional
    @Override
    public Map<String, String> getPrepayInfo(OrderDTO orderDTO) {
        //1. 封装用户端发送过来的内容
        String openId = orderDTO.getOpenId();
        String totalFee = "1";
        String desc = "测试支付";
        String orderNo = "lyy-" + UUID.randomUUID().toString().replace("-", "").substring(0, 20);


        //1.1 先插入订单表数据
        Order order = encapsulateOrder(orderDTO, orderNo);
        orderMapper.insert(order);
        //获取插入的订单id 注意将订单id返回给前端
        Integer orderId = order.getId();
        log.info("插入订单后生成的订单id为:{}", orderId);


        //1.2. 向订单详情表中插入数据 根据服务id 批量插入
        List<OrderDetails> orderDetailsList = encapsulateOrderDetails(orderDTO.getServiceIds(), orderId);
        orderDetailsMapper.insertBatch(orderDetailsList);

        //===================下面的代码固定 插入订单的数据在上面=====================
        //2. 配置商户相关的数据 注意导入的包(Config这个包)
        Config config = new RSAPublicKeyConfig.Builder()
                .merchantId(wxPayProperties.getMchId())
                .privateKeyFromPath(wxPayProperties.getMchKeyPath()) //商户私钥
                .publicKeyFromPath(wxPayProperties.getPublicKeyPath())//公钥路径
                .publicKeyId(wxPayProperties.getPublicKeyId())
                .merchantSerialNumber(wxPayProperties.getMchCertSerial())
                .apiV3Key(wxPayProperties.getApiV3Key())
                .build();
        JsapiServiceExtension jsapiServiceExtension = new JsapiServiceExtension.Builder().config(config).build();

        //3. 配置商品相关的数据 注意导入的包PrepayRequest这个包 jsapi那个
        //5个字符串 加上两个对象； 注意看微信小程序官方文档那里pay.weixin.qq.com/doc/v3/merchant/4012791856
        PrepayRequest prepayRequest = new PrepayRequest();
        prepayRequest.setAppid(wxPayProperties.getAppId()); //注意这个是商户的appid
        prepayRequest.setMchid(wxPayProperties.getMchId()); //商户号
        prepayRequest.setOutTradeNo(orderNo); //生成的订单号
        prepayRequest.setDescription(desc); //描述信息
        prepayRequest.setNotifyUrl(wxPayProperties.getNotifyUrl()); //回调地址
        //付款者对象
        Payer payer = new Payer();
        payer.setOpenid(openId); //付款者的openID
        //支付金额对象
        Amount amount = new Amount();
        amount.setTotal(Integer.parseInt(totalFee));
        amount.setCurrency("CNY");
        //放入商户请求对象中
        prepayRequest.setPayer(payer);
        prepayRequest.setAmount(amount);


        //4. 像微信服务器发请求
        //创建预支付请求 paymentResponse是预支付的响应体
        PrepayWithRequestPaymentResponse paymentResponse = jsapiServiceExtension.prepayWithRequestPayment(prepayRequest);

        //将响应体中的内容封装到map当中
        Map<String, String> map = new HashMap<>();
        map.put("timeStamp", paymentResponse.getTimeStamp());
        map.put("nonceStr", paymentResponse.getNonceStr());
        map.put("signType", paymentResponse.getSignType());
        map.put("package", paymentResponse.getPackageVal());
        map.put("paySign", paymentResponse.getPaySign());
        //封装订单id
        map.put("orderId", orderId.toString());
        log.info("预支付响应体: {}", map);

        return map;
    }

    //封装order对象
    public Order encapsulateOrder(OrderDTO orderDTO, String orderNo) {
        Order order = new Order();
        order.setVerificationCode(orderNo);
        //判断是否自带图片 没有插入默认值
        if (orderDTO.getServiceImg() == null || orderDTO.getServiceImg().isEmpty()) {
            order.setVerificationImg("https://lf-flow-web-cdn.doubao.com/obj/flow-doubao/doubao/chat/static/image/logo-icon-white-bg.72df0b1a.png");
        } else {
            order.setVerificationImg(orderDTO.getServiceImg());
        }
        order.setServiceTypeId(orderDTO.getServiceTypeID());
        order.setOrderTime(LocalDateTime.now());
        //TODO 预约时间 用到了 手动插入吧😁
        //车辆id 如果值不是 -1 就插入,否则值为空
        if (orderDTO.getCarId() != -1) {
            order.setCarId(orderDTO.getCarId());
        }
        //优惠券id 如果值不是 -1 就插入,否则值为空
        if (orderDTO.getCouponId() != -1) {
            order.setCouponId(orderDTO.getCouponId());
        }
        order.setPrice(orderDTO.getPayPrice().floatValue());
        //设置订单的支付状态是未支付的 0未支付 1已支付
        order.setPayStatus(0);
        //付费时间 还没赋值成功 使用空值 因此这里不添加
        //设置订单状态 0待支付 1已取消 2已退款 3待核销 4已完成
        order.setStatus(0);
        order.setDeleted(0);
        //默认未评价 0未评价 1已评价
        order.setEvaluate(0);
        order.setCreateBy("admin");
        order.setUpdateBy("admin");
        order.setCreateTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        return order;
    }

    //向订单详情表中批量插入数据
    public List<OrderDetails> encapsulateOrderDetails(List<Long> serviceIds, Integer orderId) {
        List<OrderDetails> orderDetailsList = new ArrayList<>();
        for (Long serviceId : serviceIds) {
            OrderDetails orderDetails = new OrderDetails();
            orderDetails.setOrderId(orderId);
            orderDetails.setServiceId(serviceId.intValue());
            orderDetails.setCreateBy("admin");
            orderDetails.setUpdateBy("admin");
            orderDetails.setCreateTime(LocalDateTime.now());
            orderDetails.setUpdateTime(LocalDateTime.now());
            orderDetailsList.add(orderDetails);
        }
        return orderDetailsList;
    }
}
